
#include <boost/bind.hpp>
#include "Channel.h"
#include "Device.h"
#include "Session.h"
#include "RequestConnect.h"
#include "proxy.h"

namespace Engine {

static void HandleWrite(ChannelRef ch, int sid, const boost::system::error_code& error)
{
	int src_id = sid == 0 ? 1 : 0;

	//DebugStream << "CChannel::HandleWrite - ";
	if (!error)
	{
		//DebugStream << " Send data to socket " << sid << " complete\n";
		ch->ScheduleRead(src_id);
	}
	else
	{
		DebugStream << " Error : " << error.message() << '\n';
		ch->Close();
	}
}

static void HandleRead(ChannelRef ch, int sid, const boost::system::error_code& error, size_t bytes_transferred)
{
	int sink_id = sid == 0 ? 1 : 0;

	//DebugStream << "CChannel::HandleRead - ";
	if (!error)
	{
		//DebugStream << "Read data from socket " << sid << ", size " << bytes_transferred << '\n';
		CChannelBuffer& buf = ch->GetBuffer(sid);
		buf.Move(bytes_transferred);
		int data_size;
		char* data = buf.GetReadPointer(data_size);
		data[data_size] = 0;
		//DebugStream << data << '\n';
		ch->GetSocket(sink_id).async_write_some(
			boost::asio::buffer(data, data_size), 
			boost::bind(&HandleWrite, ch, sink_id, boost::asio::placeholders::error)
			);
	}
	else
	{
		DebugStream << "Socket " << sid << " Error : " << error.message() << '\n';
		ch->Close();
	}
}

void CChannel::Close()
{
	DebugStream << "CChannel Closed - " << mId << '\n';
	
	if(mSocket[0] && mSocket[0]->is_open()) {
		mSocket[0]->close();
		mSocket[0].reset();
	}
	if(mSocket[1] && mSocket[1]->is_open()) {
		mSocket[1]->close();
		mSocket[1].reset();
	}

	SessionRef s = mSession.lock();
	if(s) s->DelChannel(mId);

}

void CChannel::ScheduleRead(int sid) 
{
	//DebugStream << "CChannel::ScheduleRead - Socket " << sid << '\n';

	/*
	int n = mSocket[sid]->read_some(boost::asio::buffer(mBuffers[sid], CHANNEL_BUFFER_SIZE));
	mBuffers[sid][n] = 0;

	DebugStream << "CChannel::ScheduleRead - Data readed : \n";
	DebugStream << mBuffers[sid];
	*/

	mBuffers[sid].Reset();
	int buf_size;
	char* buf = mBuffers[sid].GetWritePointer(buf_size);
	mSocket[sid]->async_read_some(
		boost::asio::buffer(buf, buf_size),
		boost::bind(&HandleRead, shared_from_this(), sid, 
		boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)
		);
	
}

bool CChannel::Connect(DeviceRef dev)
{
	string server = "proxy://" + dev->GetLocalIP() + ':' + boost::lexical_cast<string>(PROXY_PORT) + 
		"?channel=" + boost::lexical_cast<string>(mId);
	RequestRef r(new CRequestConnect(server));
	r->setEnsureSend(true);
	dev->Request(r);

	return true;
}

}